package com.yunhe.portal.service.impl;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yunhe.common.constant.MessageConsts;
import com.yunhe.common.constant.PortalConstant;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.filter.ServerContextHolder;
import com.yunhe.common.model.ResultObject;
import com.yunhe.common.model.authority.MessageCenter;
import com.yunhe.common.model.authority.RealStation;
import com.yunhe.common.model.authority.User;
import com.yunhe.common.model.base.MessageReadCount;
import com.yunhe.common.model.company.Company;
import com.yunhe.common.model.mybatis.PageResult;
import com.yunhe.common.util.DateTimeUtils;
import com.yunhe.common.util.StringUtil;
import com.yunhe.portal.client.AuthorityClient;
import com.yunhe.portal.domain.DataNewsInfo;
import com.yunhe.portal.domain.DataNoticeInfo;
import com.yunhe.portal.model.*;
import com.yunhe.portal.repository.DataNoticeInfoRepository;
import com.yunhe.portal.service.DataNoticeInfoService;
import com.yunhe.portal.util.MyHeaderUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description 公告表
 * @author misty
 * @date 2021-10-19
 */
@Service
@Slf4j
public class DataNoticeInfoServiceImpl implements DataNoticeInfoService {

    @Autowired
    private DataNoticeInfoRepository dataNoticeInfoRepository;

    @Autowired
    private MyHeaderUtil myHeaderUtil;

    @Autowired
    private AuthorityClient authorityClient;

    private static LinkedBlockingQueue<MessageCenter> dataListBOQueue = new LinkedBlockingQueue<>();


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDataNoticeInfo (DataNoticeInfo dataNoticeInfo) throws ArgumentErrorException {
        Long headerUser = myHeaderUtil.getHeaderUser();
        if(headerUser == null){
            throw new ArgumentErrorException("用户信息已过期，请重新登录！");
        }
        String projectCode = ServerContextHolder.getContext().getProjectCode();
        if(StringUtil.isEmpty(projectCode)){
            throw new ArgumentErrorException("请选择对应项目进行维护新闻！");
        }
        dataNoticeInfo.setPublishPerson(headerUser);
        if (PortalConstant.Notice_Type.Station.value().equals(dataNoticeInfo.getNoticeType())) {
            dataNoticeInfo.setStationId(projectCode);
        }
        if (StringUtil.isEmpty(dataNoticeInfo.getStatus())
                || PortalConstant.Online_Type.Published.value().equals(dataNoticeInfo.getStatus())) {
            if(dataNoticeInfo.getPublishTime().getTime() <= System.currentTimeMillis()){
                dataNoticeInfo.setStatus(PortalConstant.Online_Type.Published.value());
            }else if(!PortalConstant.Online_Type.Drafts.value().equals(dataNoticeInfo.getStatus())){
                dataNoticeInfo.setStatus(PortalConstant.Online_Type.ToBeReleased.value());
            }
        }
        dataNoticeInfoRepository.createDataNoticeInfoSelective(dataNoticeInfo);
        dataNoticeInfo.setNoticeUrl(dataNoticeInfo.getNoticeUrl()+dataNoticeInfo.getId());
        dataNoticeInfoRepository.updateDataNoticeInfoByPrimaryKeySelective(dataNoticeInfo);
        if(PortalConstant.Online_Type.Published.value().equals(dataNoticeInfo.getStatus())){
            try {
                sendMessageCenter(dataNoticeInfo,headerUser);
                pushMessageToApp(projectCode, dataNoticeInfo);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            //创建新的线程发送到消息中心
//            new Thread(()-> {
//                try {
//                    sendMessageCenter(dataNoticeInfo,headerUser);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }).start();
        }

    }

    private void pushMessageToApp(String projectCode, DataNoticeInfo dataNoticeInfo) {
        //消息推送（App只面向园区推送）
        if(PortalConstant.Notice_Type.Station.value().equals(dataNoticeInfo.getNoticeType())) {
            Map<String, String> extras = new HashMap<>();
            extras.put("stationId", projectCode);
//            String content = dataNoticeInfo.getContent().length() > 15 ? dataNoticeInfo.getContent().substring(0, 14) + "......" : dataNoticeInfo.getContent();
            String content = dataNoticeInfo.getSubtitle();
            authorityClient.pushMessageByStationId(Long.valueOf(projectCode), "公告", content, extras);
        }
    }

    private void sendMessageCenter(DataNoticeInfo dataNoticeInfo,Long headerUser) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        //创建线程池 批量处理数据
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {
            batchDataProcessing();
        });
        if(PortalConstant.Notice_Type.Station.value().equals(dataNoticeInfo.getNoticeType())){
            //查询 园区用户推送公告信息
            ResponseEntity<ResultObject<List<User>>> responseEntity = authorityClient.findStationUserByStationId(Long.valueOf(dataNoticeInfo.getStationId()));
            if(responseEntity != null){
                if(responseEntity.getStatusCode().is2xxSuccessful()){
                    Object results = responseEntity.getBody().getResults();
                    List<User> users = JSON.parseArray(JSON.toJSONString(results), User.class);
                    if(!CollectionUtils.isEmpty(users)){
                        for (User user : users) {
                            MessageCenter messageCenter = new MessageCenter();
                            messageCenter.setBusinessId(dataNoticeInfo.getId());
                            messageCenter.setMessageDestination(MessageConsts.MessageDestination.parkApp.value());
                            messageCenter.setMessageTime(DateTimeUtils.format(DateTimeUtils.PATTERN.DATETIME.value(), new Date()));
                            messageCenter.setMessageType(MessageConsts.MessageType.Notice.value());
                            messageCenter.setMessagePerson(user.getId());
                            messageCenter.setContent(JSON.toJSONString(dataNoticeInfo));
                            messageCenter.setMessageSendPerson(headerUser);
                            messageCenter.setPersonType(MessageConsts.PersonType.StationUser.value());
                            dataListBOQueue.add(messageCenter);
                        }
                    }
                }
            }
        }else if(PortalConstant.Notice_Type.Company.value().equals(dataNoticeInfo.getNoticeType())){
            String[] split = dataNoticeInfo.getStationId().split(",");
            for (String s : split) {
                ResponseEntity<ResultObject<List<Company>>> responseEntity = authorityClient.findCompanyByRealStationId(Long.valueOf(s));
                if(responseEntity != null){
                    if(responseEntity.getStatusCode().is2xxSuccessful()){
                        Object results = responseEntity.getBody().getResults();
                        List<Company> companies = JSON.parseArray(JSON.toJSONString(results), Company.class);
                        if(!CollectionUtils.isEmpty(companies)){
                            for (Company company : companies) {
                                MessageCenter messageCenter = new MessageCenter();
                                messageCenter.setBusinessId(dataNoticeInfo.getId());
                                messageCenter.setMessageDestination(MessageConsts.MessageDestination.parkWeChat.value());
                                messageCenter.setMessageTime(DateTimeUtils.format(DateTimeUtils.PATTERN.DATETIME.value(), new Date()));
                                messageCenter.setMessageType(MessageConsts.MessageType.Notice.value());
                                messageCenter.setCompanyId(company.getId());
                                messageCenter.setContent(JSON.toJSONString(dataNoticeInfo));
                                messageCenter.setMessageSendPerson(headerUser);
                                messageCenter.setPersonType(MessageConsts.PersonType.CompanyUser.value());
                                dataListBOQueue.add(messageCenter);
                            }
                        }
                    }
                }
            }
        }

        dataListBOQueue.add(new MessageCenter());
        long endTime = System.currentTimeMillis();
        log.info("数据处理所需时间：{}",(endTime-startTime));
        log.info("数据处理结束");
        executorService.shutdown();
        executorService.awaitTermination(20, TimeUnit.SECONDS);
    }

    private void batchDataProcessing() {
        try {
            for (; ; ) {
                List<MessageCenter> dataLists = new ArrayList<>(100);
                for (int i = 0; i < 50; i++) {
                    MessageCenter take = dataListBOQueue.take();
                    if (take == null || take.getBusinessId() ==null) {
                        if (!CollectionUtils.isEmpty(dataLists)) {
                            authorityClient.batchCreateMessageCenter(dataLists);
                        }
                        return;
                    } else {
                        dataLists.add(take);
                    }
                }
                if (!CollectionUtils.isEmpty(dataLists)) {
                    authorityClient.batchCreateMessageCenter(dataLists);
                    dataLists.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteDataNoticeInfo(int id) {
        return dataNoticeInfoRepository.deleteDataNoticeInfoByPrimaryKey(id);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDataNoticeInfo(DataNoticeInfo dataNoticeInfo) throws ArgumentErrorException {
        Long headerUser = myHeaderUtil.getHeaderUser();
        if(headerUser == null){
            throw new ArgumentErrorException("用户信息已过期，请重新登录！");
        }
        dataNoticeInfo.setUpdatePerson(headerUser);
        if (StringUtil.isEmpty(dataNoticeInfo.getStatus())
                || PortalConstant.Online_Type.Published.value().equals(dataNoticeInfo.getStatus())) {
            if(dataNoticeInfo.getPublishTime().getTime() <= System.currentTimeMillis()){
                dataNoticeInfo.setStatus(PortalConstant.Online_Type.Published.value());
                dataNoticeInfo.setPublishPerson(headerUser);
            }
        }
        dataNoticeInfoRepository.updateDataNoticeInfoByPrimaryKeySelective(dataNoticeInfo);
        if(PortalConstant.Online_Type.Published.value().equals(dataNoticeInfo.getStatus())){
            //创建新的线程发送到消息中心
            new Thread(()-> {
                try {
                    sendMessageCenter(dataNoticeInfo,headerUser);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }


    @Override
    public DataNoticeInfo findDataNoticeInfoById(int id) {
        DataNoticeInfo dataNoticeInfo = dataNoticeInfoRepository.searchDataNoticeInfoByPrimaryKey(id);
        //查询消息已读未读条数
        ResponseEntity<ResultObject<MessageReadCount>> responseEntity
                = authorityClient.getMessageCountByCondition(dataNoticeInfo.getId(), MessageConsts.MessageType.Notice.value());
        if(responseEntity != null){
            if (responseEntity.getStatusCode().is2xxSuccessful()) {
                Object results = responseEntity.getBody().getResults();
                MessageReadCount messageReadCount = JSON.parseObject(JSON.toJSONString(results),MessageReadCount.class);
                if(messageReadCount != null){
                    dataNoticeInfo.setReadCount(messageReadCount.getReadCount() == null?0:messageReadCount.getReadCount());
                    dataNoticeInfo.setUnReadCount(messageReadCount.getUnReadCount() == null?0:messageReadCount.getUnReadCount());
                }
            }
        }
        return dataNoticeInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setPublishStatus(PublishStatus publishStatus) throws ArgumentErrorException {
        Long headerUser = myHeaderUtil.getHeaderUser();
        if(headerUser == null){
            throw new ArgumentErrorException("用户信息已过期，请重新登录！");
        }
        List<Long> ids = publishStatus.getIds();
        if(!CollectionUtils.isEmpty(ids)){
            for (Long id : ids) {
                DataNoticeInfo dataNoticeInfo = new DataNoticeInfo();
                dataNoticeInfo.setId(id);
                if(PortalConstant.Online_Type.Published.value().equals(publishStatus.getPublishStatus())){
                    DataNoticeInfo dataNoticeInfo1 = dataNoticeInfoRepository.searchDataNoticeInfoByPrimaryKey(Math.toIntExact(id));
                    if(dataNoticeInfo1.getPublishTime().getTime() <= System.currentTimeMillis() &&
                            PortalConstant.Online_Type.ToBeReleased.value().equals(dataNoticeInfo1.getStatus())){
                        dataNoticeInfo.setStatus(PortalConstant.Online_Type.Published.value());
                        dataNoticeInfo.setPublishPerson(headerUser);
                    }
                    dataNoticeInfo.setActivity("1");
                }else if(PortalConstant.Online_Type.Disable.value().equals(publishStatus.getPublishStatus())){
                    dataNoticeInfo.setActivity("0");
                }
                dataNoticeInfo.setUpdatePerson(headerUser);
                dataNoticeInfoRepository.updateDataNoticeInfoByPrimaryKeySelective(dataNoticeInfo);
            }
            if(PortalConstant.Online_Type.Published.value().equals(publishStatus.getPublishStatus())){
                new Thread(()-> {
                    try {
                        for (Long id : ids) {
                            DataNoticeInfo dataNoticeInfo = findDataNoticeInfoById(Math.toIntExact(id));
                            if((dataNoticeInfo.getPublishTime().getTime() <= System.currentTimeMillis() &&
                                    PortalConstant.Online_Type.ToBeReleased.value().equals(dataNoticeInfo.getStatus())) ||
                                    PortalConstant.Online_Type.Published.value().equals(dataNoticeInfo.getStatus())){
                                if(dataNoticeInfo != null){
                                    sendMessageCenter(dataNoticeInfo,headerUser);
                                }
                            }

                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }

    }

    @Override
    public PageResult findDataNoticeInfoByCondition(NoticeInfoQueryCondition noticeInfoQueryCondition) throws ArgumentErrorException {
        PageResult result = null;
        String projectCode = ServerContextHolder.getContext().getProjectCode();
        if(StringUtil.isEmpty(projectCode)){
            throw new ArgumentErrorException("请选择对应项目进行维护新闻！");
        }
        List<DataNoticeInfoVo> dataNoticeInfoVos = new ArrayList<>();
        noticeInfoQueryCondition.setStationId(Long.valueOf(projectCode));
        if (PortalConstant.Notice_Type.Station.value().equals(noticeInfoQueryCondition.getNoticeType())) {
            PageHelper.startPage(noticeInfoQueryCondition.getPage(),noticeInfoQueryCondition.getSize());
            dataNoticeInfoVos = dataNoticeInfoRepository.findStationDataNoticeInfoByCondition(noticeInfoQueryCondition);
        }else if(PortalConstant.Notice_Type.Company.value().equals(noticeInfoQueryCondition.getNoticeType())){
            if(CollectionUtils.isEmpty(noticeInfoQueryCondition.getRealStationIds())){
                //查询当前项目下所有真实园区
                List<Long> stationIds = new ArrayList<>();
                ResponseEntity<ResultObject> responseEntity = authorityClient.searchStationAndOfficeByStationId(Long.valueOf(projectCode));
                if (responseEntity != null) {
                    if (responseEntity.getStatusCode().is2xxSuccessful()) {
                        Object results = responseEntity.getBody().getResults();
                        List<RealStation> realStations = JSON.parseArray(JSON.toJSONString(results), RealStation.class);
                        for (RealStation realStation : realStations) {
                            stationIds.add(realStation.getId());
                        }
                    }
                }
                noticeInfoQueryCondition.setRealStationIds(stationIds);
            }
            PageHelper.startPage(noticeInfoQueryCondition.getPage(),noticeInfoQueryCondition.getSize());
            dataNoticeInfoVos = dataNoticeInfoRepository.findCompanyDataNoticeInfoByCondition(noticeInfoQueryCondition);
        }
        if(!CollectionUtils.isEmpty(dataNoticeInfoVos)){
            PageInfo<DataNoticeInfoVo> pageInfo = new PageInfo<>(dataNoticeInfoVos);
            result = new PageResult(noticeInfoQueryCondition.getPage(),noticeInfoQueryCondition.getSize(), (int) pageInfo.getTotal(),dataNoticeInfoVos);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishTimedNotices() {
        //查询需要发布的公告进行发布
        List<DataNoticeInfo> noticeInfos = dataNoticeInfoRepository.findNeedPublishTimedNotices();
        if(!CollectionUtils.isEmpty(noticeInfos)){
            List<Long> ids = noticeInfos.stream().map(DataNoticeInfo::getId).collect(Collectors.toList());
            dataNoticeInfoRepository.publishTimedNotices(ids);
            try {
                for (DataNoticeInfo noticeInfo : noticeInfos) {
                    sendMessageCenter(noticeInfo,noticeInfo.getPublishPerson());
                    pushMessageToApp(noticeInfo.getStationId(), noticeInfo);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            new Thread(()-> {
//                try {
//                    for (DataNoticeInfo noticeInfo : noticeInfos) {
//                        sendMessageCenter(noticeInfo,noticeInfo.getPublishPerson());
//                    }
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }).start();
        }
    }


    @Override
    public PageResult findAppNotice(PhoneQueryCondition phoneQueryCondition) {
        PageResult result = null;
        PageHelper.startPage(phoneQueryCondition.getPage(), phoneQueryCondition.getSize());
        List<DataPhoneNoticeInfoVo> dataNewsInfoVos = dataNoticeInfoRepository.findPhonesNoticeByCondition(phoneQueryCondition);
        if(!CollectionUtils.isEmpty(dataNewsInfoVos)){
            PageInfo<DataPhoneNoticeInfoVo> pageInfo = new PageInfo<>(dataNewsInfoVos);
            result = new PageResult(phoneQueryCondition.getPage(), phoneQueryCondition.getSize(), (int) pageInfo.getTotal(),dataNewsInfoVos);
        }
        return result;
    }

    @Override
    public PageResult findWeChatNotice(PhoneQueryCondition phoneQueryCondition) {
        PageResult result = null;
        PageHelper.startPage(phoneQueryCondition.getPage(), phoneQueryCondition.getSize());
        List<DataPhoneNoticeInfoVo> dataNewsInfoVos = dataNoticeInfoRepository.findPhonesNoticeByCondition(phoneQueryCondition);
        if(!CollectionUtils.isEmpty(dataNewsInfoVos)){
            PageInfo<DataPhoneNoticeInfoVo> pageInfo = new PageInfo<>(dataNewsInfoVos);
            result = new PageResult(phoneQueryCondition.getPage(), phoneQueryCondition.getSize(), (int) pageInfo.getTotal(),dataNewsInfoVos);
        }
        return result;
    }

    @Override
    public DataNoticeInfo findPhoneDataNoticeInfoById(int id) {
        return dataNoticeInfoRepository.searchDataNoticeInfoByPrimaryKey(id);
    }


}